import React, { Suspense, useRef, useState, useCallback, CSSProperties, JSX } from 'react'
import { Canvas, useThree, ThreeEvent } from '@react-three/fiber'
import { OrbitControls, useGLTF, ContactShadows } from '@react-three/drei'
import * as THREE from 'three'

interface SelectedVertex {
  mesh: THREE.Mesh
  vertexIndex: number
  originalPosition: THREE.Vector3
}

interface DeformableShoeProps {
  position?: [number, number, number]
}

function DeformableShoe({ position = [0, -0.3, 0] }: DeformableShoeProps): JSX.Element {
  const { scene } = useGLTF('/models/shoe.glb')
  const meshRef = useRef<THREE.Group>(null)
  const originalPositions = useRef<Map<string, Float32Array>>(new Map())
  const [isDeforming, setIsDeforming] = useState<boolean>(false)
  const [selectedVertex, setSelectedVertex] = useState<SelectedVertex | null>(null)
  const { camera, raycaster, pointer } = useThree()

  // 克隆场景以避免修改原始数据
  const clonedScene = scene.clone()
  
  // 初始化：保存原始顶点位置
  React.useEffect(() => {
    clonedScene.traverse((child) => {
      if (child instanceof THREE.Mesh && child.geometry) {
        const geometry = child.geometry
        if (!geometry.attributes.position) return
        
        // 确保几何体可编辑
        if (geometry.index) {
          // 如果有索引，转换为非索引几何体
          const newGeometry = geometry.toNonIndexed()
          child.geometry = newGeometry
        }
        
        // 保存原始位置
        const positions = child.geometry.attributes.position.array as Float32Array
        originalPositions.current.set(child.uuid, new Float32Array(positions))
      }
    })
  }, [clonedScene])

  // 鼠标按下：检测点击的顶点
  const handlePointerDown = useCallback((event: ThreeEvent<PointerEvent>) => {
    const nativeEvent = event.nativeEvent
    if (nativeEvent.shiftKey) { // 按住 Shift 进入变形模式
      event.stopPropagation()
      setIsDeforming(true)
      
      // 射线检测
      raycaster.setFromCamera(pointer, camera)
      const intersects = raycaster.intersectObject(clonedScene, true)
      
      if (intersects.length > 0) {
        const intersect = intersects[0]
        const mesh = intersect.object as THREE.Mesh
        const faceIndex = intersect.faceIndex as number
        
        if (mesh.geometry && faceIndex !== undefined) {
          // 获取面的顶点索引
          const geometry = mesh.geometry
          const positions = geometry.attributes.position
          
          // 找到最近的顶点
          const face = new THREE.Triangle()
          face.setFromAttributeAndIndices(positions, faceIndex * 3, faceIndex * 3 + 1, faceIndex * 3 + 2)
          
          const point = intersect.point.clone()
          mesh.worldToLocal(point)
          
          // 找到距离点击点最近的顶点
          let closestVertexIndex = faceIndex * 3
          let minDistance = Infinity
          
          for (let i = 0; i < 3; i++) {
            const vertexIndex = faceIndex * 3 + i
            const vertex = new THREE.Vector3(
              positions.getX(vertexIndex),
              positions.getY(vertexIndex),
              positions.getZ(vertexIndex)
            )
            const distance = point.distanceTo(vertex)
            if (distance < minDistance) {
              minDistance = distance
              closestVertexIndex = vertexIndex
            }
          }
          
          setSelectedVertex({
            mesh,
            vertexIndex: closestVertexIndex,
            originalPosition: new THREE.Vector3(
              positions.getX(closestVertexIndex),
              positions.getY(closestVertexIndex),
              positions.getZ(closestVertexIndex)
            )
          })
        }
      }
    }
  }, [camera, raycaster, pointer, clonedScene])

  // 鼠标移动：变形顶点
  const handlePointerMove = useCallback((event: ThreeEvent<PointerEvent>) => {
    if (isDeforming && selectedVertex) {
      event.stopPropagation()
      
      // 计算鼠标移动量
      const nativeEvent = event.nativeEvent
      const movementX = nativeEvent.movementX || 0
      const movementY = nativeEvent.movementY || 0
      
      const { mesh, vertexIndex } = selectedVertex
      const positions = mesh.geometry.attributes.position
      
      // 根据鼠标移动调整顶点位置
      const sensitivity = 0.01
      const currentX = positions.getX(vertexIndex)
      const currentY = positions.getY(vertexIndex)
      const currentZ = positions.getZ(vertexIndex)
      
      positions.setX(vertexIndex, currentX + movementX * sensitivity)
      positions.setY(vertexIndex, currentY - movementY * sensitivity)
      
      // 影响周围顶点（柔和变形）
      const influenceRadius = 0.2
      const selectedPos = new THREE.Vector3(currentX, currentY, currentZ)
      
      for (let i = 0; i < positions.count; i++) {
        if (i === vertexIndex) continue
        
        const pos = new THREE.Vector3(
          positions.getX(i),
          positions.getY(i),
          positions.getZ(i)
        )
        
        const distance = selectedPos.distanceTo(pos)
        if (distance < influenceRadius) {
          const influence = 1 - (distance / influenceRadius)
          const factor = influence * 0.3 // 影响强度
          
          positions.setX(i, positions.getX(i) + movementX * sensitivity * factor)
          positions.setY(i, positions.getY(i) - movementY * sensitivity * factor)
        }
      }
      
      positions.needsUpdate = true
      mesh.geometry.computeVertexNormals() // 重新计算法线
    }
  }, [isDeforming, selectedVertex])

  // 鼠标抬起：结束变形
  const handlePointerUp = useCallback(() => {
    setIsDeforming(false)
    setSelectedVertex(null)
  }, [])

  // 重置变形
  const resetDeformation = useCallback(() => {
    clonedScene.traverse((child) => {
      if (child instanceof THREE.Mesh && child.geometry && originalPositions.current.has(child.uuid)) {
        const originalPos = originalPositions.current.get(child.uuid)!
        const positions = child.geometry.attributes.position
        positions.array.set(originalPos)
        positions.needsUpdate = true
        child.geometry.computeVertexNormals()
      }
    })
  }, [clonedScene])

  // 键盘事件：R 键重置
  React.useEffect(() => {
    const handleKeyPress = (event: KeyboardEvent): void => {
      if (event.key === 'r' || event.key === 'R') {
        resetDeformation()
      }
    }
    window.addEventListener('keydown', handleKeyPress)
    return () => window.removeEventListener('keydown', handleKeyPress)
  }, [resetDeformation])

  return (
    <primitive 
      ref={meshRef}
      object={clonedScene} 
      position={position}
      onPointerDown={handlePointerDown}
      onPointerMove={handlePointerMove}
      onPointerUp={handlePointerUp}
    />
  )
}

useGLTF.preload('/models/shoe.glb')

export default function ThreeDemo(): JSX.Element {
  const containerStyle: CSSProperties = {
    width: '100vw', 
    height: 'calc(100vh - 60px)'
  }

  const instructionStyle: CSSProperties = {
    position: 'absolute',
    top: 80,
    left: 20,
    color: 'white',
    background: 'rgba(0,0,0,0.7)',
    padding: '10px',
    borderRadius: '5px',
    fontSize: '14px',
    zIndex: 1000
  }

  const titleStyle: CSSProperties = {
    marginBottom: '5px', 
    fontWeight: 'bold', 
    color: '#4CAF50'
  }

  // 基于屏幕像素的阴影平面偏移
  function ShadowOffsetContactShadows({
    baseY = -0.8,
    pixelOffset = 100
  }: { baseY?: number; pixelOffset?: number }): JSX.Element {
    const { camera, size } = useThree()

    const y = React.useMemo(() => {
      const p = new THREE.Vector3(0, baseY, 0)
      const ndc = p.clone().project(camera) // NDC 空间
      // 屏幕向下是 +px，但 NDC 的向下是 -，所以取负号
      const ndcDeltaY = -(pixelOffset / size.height) * 2
      const ndc2 = new THREE.Vector3(ndc.x, ndc.y + ndcDeltaY, ndc.z)
      const w2 = ndc2.clone().unproject(camera)
      const deltaY = w2.y - p.y
      return baseY + deltaY
    }, [camera, size.height, baseY, pixelOffset])

    return (
      <ContactShadows position={[0, y, 0]} opacity={0.5} scale={5} blur={2} far={2} />
    )
  }

  return (
    <div style={containerStyle}>
      {/* 操作提示 */}
      <div style={instructionStyle}>
        <div style={titleStyle}>
          🎮 Three.js 演示
        </div>
        <div>🖱️ 普通拖拽：旋转视角</div>
        <div>⇧ + 拖拽：变形模型</div>
        <div>🔄 按 R 键：重置变形</div>
        <div>🖱️ 滚轮：缩放</div>
      </div>
      
      <Canvas shadows camera={{ position: [0, 0.8, 2], fov: 45 }} dpr={[1, 2]}>
        <ambientLight intensity={0.5} />
        <directionalLight position={[3, 3, 3]} intensity={0.8} castShadow />
        <Suspense fallback={null}>
          <DeformableShoe position={[0, -0.3, 0]} />
        </Suspense>
        {/* 替换原来的 ContactShadows 为屏幕像素驱动的版本 */}
        <ShadowOffsetContactShadows baseY={-0.8} pixelOffset={150} />
        <OrbitControls 
          enablePan 
          enableZoom 
          enableRotate 
          target={[0, -0.3, 0]}
          minDistance={0.5}
          maxDistance={5}
        />
      </Canvas>
    </div>
  )
}